# list （数组）
from typing import Iterator


a = [1,2,3,4,5]
# 相当于push
a.append(1)
print(a)
# 长度
print(len(a))
# 循环
for i in a:
    print(i)
a.insert(0, 0) # insert 在某个位置插入
print(a)
# range(n) 生成0-n内所有的整数
arr = list(range(100))
for i in arr:
    if i == 99:
        print(i,'----')

for i in range(10):
    print(i,'___')
#-------------------------------------------------------



#  tuple 元组（固定元素的数组，更安全） 元素一声明，元素的个数和种类就被确定下来了
c = (1,2,3,4,5)
print(c)
for i in c:
    print(i)
# 只有一个元素的时候
d = (1,) # ，消除小括号的歧义
#-------------------------------------------------------



# 条件判断
e = [1,2,3,4,5]
if len(a) < 5:
    print('小于5')
elif len(a) == 5:
    print('等于5')
else:
    print('大于5')
#-------------------------------------------------------



# dic 字典（相当于map）
per = {
    'name': 1,
    'age': 0
}
print(per)
print(per['name'])
# 修改属性
per['name'] = 2;
print(per['name'])
# 判断key是否存在
if 'name' in per:
    print('有名字这个属性')
# get 返回返回value
print(per.get('name'));
print(per.get('a')); # 不存在的属性返回none
#-------------------------------------------------------



# set 数据结构  和js一样 add() 添加， remove() 删除
s = set([1,5,6,7,1,1]) # 去重
print(s)
#-------------------------------------------------------



# 函数
# return None可以简写为return
def pritnName (name):
    print(name)
    return
print(pritnName('asda'))
# 定义一个空函数
def aaa ():
    pass # 用来作为占位符
# 返回多个值
def calculate():
    x = 1
    y = 2
    return x, y
aa, bb = calculate()
print(aa, bb)
# 函数的参数:
# 必备参数
def fffn(a, b):
    print(a, b)
fffn('zzzzzzzzzzzz', 'xxxxxxxxxxx')

# 函数的可变参数
# *args是可变参数，args接收的是一个tuple；数组
# **kw是关键字参数，kw接收的是一个dict 字典 关键字参数允许你传入0个或任意个含参数名的参数，这些关键字参数在函数内部自动组装为一个dict。

def getAAA(name, age, *args):
    print(name, age, args)
    return
getAAA(1,2,'a', 'b') # 1 2 ('a', 'b')
def person(name, age, **kw):
    print(name, age, kw)
person(1, 2)
person('Bob', 35, city='Beijing', sex = 'man')
#-----------------------------------------------------



# 切片  //方便操作数组
slice_a = [1,2,3,45]
all = slice_a[:] # 所有
front_3 = slice_a[:3] # 0-2
f_1_end_aell = slice_a[1:] # 1 - n
print(all)
print(front_3)
print(f_1_end_aell)




# 迭代 字典
obj = {
    'name': 1,
    'age': 2
}
# 迭代 key 和 value
for k, v in obj.items():
    print(k, v)
# 迭代key
for k in  obj:
    print(k)
# 迭代value
for v in  obj.values():
    print(v)
# ------------------------------




# 迭代字符串

str = 'adasda'

for i in str:
    print(i)
# ------------------------------



# 列表生成器
# Python内置的非常简单却强大的可以用来创建list的生成式。

res = list(range(1,11))
print(res)
res1 = [x * x for x in range(1, 11)] # 每一项时 x^2
print(res1)
res2 = [x * x for x in range(1, 11) if x == 10] #只返回 x = 10 的这一项值为： x^2
print(res2)
res3 = [x * x if x==10 else -x for x in range(1,11)] # x = 10 的这一项的值位x^2 其余的位 -x
print(res3)
# ------------------------------



# 生成器 
# 在Python中，这种一边循环一边计算的机制，称为生成器：generator。 可以用next() 访问下一个元素， 一般用for 就可以
ger = (x * x for x in range(11))
print(ger) #<generator object <genexpr> at 0x000001B013418EB0>
print(next(ger)) # 0
print(next(ger)) # 1
print(next(ger)) # 4
for i in ger:
    print(i)
# 这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字，那么这个函数就不再是一个普通函数，而是一个generator：
# 而变成generator的函数，在每次调用next()的时候执行，遇到yield语句返回，再次执行时从上次返回的yield语句处继续执行。
def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b
        a, b = b, a + b
        n = n + 1
    return 'done'
# ------------------------------



# 迭代器
# 可以使用isinstance()判断一个对象是否是Iterable对象：
from collections.abc import Iterable
isins = isinstance([1,  2], Iterable)
print(isins)
# ------------------------------



# 高阶函数之 map 和 reduce
# 我们先看map。map()函数接收两个参数，一个是函数，一个是Iterable，map将传入的函数依次作用到序列的每个元素，并把结果作为新的Iterator返回。

def f(x):
    return x * x
ll = list(map(f, range(1,11)))
print(ll)

# reduce把一个函数作用在一个序列[x1, x2, x3, ...]上，这个函数必须接收两个参数，reduce把结果继续和序列的下一个元素做累积计算
from functools import reduce
def add(x, y):
    return x + y
rr = reduce(add, [1, 3, 5, 7, 9])
print(rr)

# filter()把传入的函数依次作用于每个元素，然后根据返回值是True还是False决定保留还是丢弃该元素
def is_odd(n):
    return n % 2 == 0
ff = list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15]))
print(ff)

# 排序 默认升序 
ss = sorted([36, 5, -12, 9, -21])
print(ss)

# 自定义排序规则
ss1 = sorted([36, 5, -12, 9, -21], key = abs)
print(ss1)
# ------------------------------




# 匿名函数 
lambda x: x * x  # 相当于

def fn (x):
    return x * x



# 装饰器
# 函数即对象 
ccc = fn
ccc(1)

ccc.__name__ # fn 拿到函数的名字

## 装饰器 decorator就是一个返回函数的高阶函数。所以，我们要定义一个能打印日志的decorator，可以定义如下
def log(func):
    def wrapper(*args, **kw):
        print('call %s():' % func.__name__)
        return func(*args, **kw)
    return wrapper
@log
def now():
    print('2015-3-25')

now() # 调用now()函数，不仅会运行now()函数本身，还会在运行now()函数前打印一行日志：
# call now(): 
# 2015-3-25 
# 把@log放到now()函数的定义处，相当于执行了语句：now = log(now)
# 由于log()是一个decorator，返回一个函数，所以，原来的now()函数仍然存在，只是现在同名的now变量指向了新的函数，于是调用now()将执行新函数，即在log()函数中返回的wrapper()函数。
# wrapper()函数的参数定义是(*args, **kw)，因此，wrapper()函数可以接受任意参数的调用。在wrapper()函数内，首先打印日志，再紧接着调用原始函数。

# 装饰器传参
# 如果decorator本身需要传入参数，那就需要编写一个返回decorator的高阶函数，写出来会更复杂
def log1(text):
    def decorator(func):
        def wrapper(*args, **kw):
            print(text)
            return func(*args, **kw)
        return wrapper
    return decorator

@log1('execute')
def now1():
    print('2015-3-25')

now1()
# 和两层嵌套的decorator相比，3层嵌套的效果是这样的：
# now = log('execute')(now)
# ------------------------------




# 偏函数
# functools.partial就是帮助我们创建一个偏函数的，不需要我们自己定义int2()，可以直接使用下面的代码创建一个新的函数int2：
import functools
int2 = functools.partial(int, base=2)
int2('1000000') # 64